package com.example.poselib

import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.util.Log
import com.example.poselib.VisualizationUtils.bodyJoints
import com.example.poselib.data.SimilarData
import com.example.poselib.ml.MoveNetMultiPose
import com.example.poselib.ml.PoseDetector
import com.example.poselib.ml.Type
import com.example.poselib.data.Device
import com.example.poselib.data.Person
import java.util.*
import kotlin.math.abs
import kotlin.math.atan

/**
 *动作制造
 * */
class PoseMaker(private val context: Context) {
    private val TAG = "PoseMaker"

    //动作探测器
    private var detector: PoseDetector? = null
    private var fpsTimer: Timer? = null
    private var frameProcessedInOneSecondInterval = 0
    private var framesPerSecond = 0
    private val MIN_CONFIDENCE = .2f
    private var isTrackerEnabled = true

    private val paintCircle = Paint().apply {
        strokeWidth = 2f
        color = Color.YELLOW
        style = Paint.Style.STROKE
    }

    //扣分基数
    private val deductionBase: Float = 100.0f / bodyJoints.size.toFloat()

    // 锁
    private val lock = Any()

    init {
        initDetector(context)
    }

    private fun initDetector(context: Context) {
        synchronized(lock) {
            if (this.detector != null) {
                this.detector?.close()
                this.detector = null
            }
            detector = MoveNetMultiPose.create(
                context,
                Device.CPU,
                Type.Dynamic
            )
        }
    }

    fun getPoses(bitmap: Bitmap): List<Person> {
        val persons = mutableListOf<Person>()
        synchronized(lock) {
            detector?.estimatePoses(bitmap)?.let {
                persons.addAll(it)
            }
        }
        return persons
    }

    // process image
    fun processImage(bitmap: Bitmap): Bitmap {
        val persons = mutableListOf<Person>()
        synchronized(lock) {
            detector?.estimatePoses(bitmap)?.let {
                persons.addAll(it)
            }
        }
        return visualize(persons, bitmap)
    }

    fun similarScore(standardBitmap: Bitmap, targetBitmap: Bitmap): SimilarData {
        val result = SimilarData(targetBitmap, 0)
        synchronized(lock) {
            //标准图片的结果
            val standardPoses = detector?.estimatePoses(standardBitmap)
            //需要检测的结果
            val targetPoses = detector?.estimatePoses(targetBitmap)
            if (standardPoses?.isEmpty() == true || targetPoses?.isEmpty() == true) {
                return result
            }
            val drawBitmap = visualize(targetPoses!!, targetBitmap)
            val canvas = Canvas(drawBitmap)
            val standardPose = standardPoses!![0]
            val targetPose = targetPoses!![0]
            var deductionScores = 0.0f
            //每个关键点之间的关系
            bodyJoints?.forEach {
                //获取相近两个点
                val standPointA = standardPose.keyPoints[it.first.position].coordinate
                val standPointB = standardPose.keyPoints[it.second.position].coordinate
                val targetPointA = targetPose.keyPoints[it.first.position].coordinate
                val targetPointB = targetPose.keyPoints[it.second.position].coordinate

                //计算两点之间的夹角
                /**
                 * 公式1：角度：Math.toDegress(Math.atan((bx-ax)/(by-ay)) )
                 * 公式：
                 * 扣分基数：deductionBase=(100/18)=5.5
                 * standParameter=（Bx-Ax）/(By-Ay)
                 * targetParameter=（Bx-Ax）/(By-Ay)
                 * 扣分=(standParameter-targetParameter)*deductionBase
                 * 最后得分等于：总分100-累计扣分
                 * */
                Log.i(TAG, "standPointA: $standPointA")
                Log.i(TAG, "standPointB: $standPointB")
//
                Log.i(TAG, "targetPointA: $targetPointA")
                Log.i(TAG, "targetPointB: $targetPointB")
                val standPointX =(standPointB.x - standPointA.x)
                val standPointY = (standPointB.y - standPointA.y)
                var standDegree=0.0
                standDegree = if(standPointY==0f){
                    90.0
                }else{
                    val standParameter = standPointY / standPointX
                    val standAtan = atan(standParameter.toDouble())
                    Log.i(TAG, "standAtan: $standAtan")
                    Math.toDegrees(standAtan)
                }
                Log.i(TAG, "standDegree: $standDegree")
                val targetPointX =(targetPointB.x - targetPointA.x)
                val targetPointY = (targetPointB.y - targetPointA.y)
                var targetDegree=0.0
                targetDegree = if(targetPointY==0f){
                    90.0
                }else{
                    val targetParameter = targetPointY / targetPointX
                    val targetAtan = atan(targetParameter.toDouble())
                    Log.i(TAG, "targetAtan: $targetAtan")
                    Math.toDegrees(targetAtan)
                }
                Log.i(TAG, "targetDegree: $targetDegree")
                Log.i(TAG, "deduction before: "+(standDegree - targetDegree))
                //偏差角度，区分正反，如果是负数，则需要用180减去
                var deduction = abs((standDegree - targetDegree) / 180)
                Log.i(TAG, "deduction: $deduction")
                var deductionScore: Float = (deduction * deductionBase).toFloat()
                Log.i(TAG, "deductionScore: $deductionScore")
                if (deduction >= 0.12f) {
                    Log.e(TAG, "similarScore: $deductionScore")
                    canvas.drawCircle(
                        targetPointA.x + (targetPointB.x - targetPointA.x) / 2f,
                        targetPointA.y + (targetPointB.y - targetPointA.y) / 2f,
                        8f,
                        paintCircle
                    )
                    deductionScore=deductionBase
                }
                Log.i(TAG, "${it.first.position} deductionScore: " + deductionScore)
                deductionScores += deductionScore
                Log.e(TAG, "deductionScores: $deductionScores")
            }
            result.resultBitmap = drawBitmap
            result.similarScore = (100.0f - deductionScores).toInt()
        }
        return result
    }

    private fun visualize(persons: List<Person>, bitmap: Bitmap): Bitmap {
        return VisualizationUtils.drawBodyKeypoints(
            bitmap,
            persons.filter { it.score > MIN_CONFIDENCE }, isTrackerEnabled
        )
    }
}